
{***********************************************************}
{                                                           }
{      Luxena dbExpress eXtension Components                }
{                                                           }
{      TDBXConnection component                             }
{                                                           }
{      Copyright (c) 2001-2006 Luxena Software Company      }
{      http://www.luxena.com                                }
{      e-mail: support@luxena.com                           }
{                                                           }
{***********************************************************}

unit DBXConnection;

{$I lx.inc}

interface

uses
  Classes, DBXpress, SqlExpr, LXResourcePool, DBXSQLProcessor;


type

{ TDBXConnection }

  TDBXConnection = class(TSQLConnection)
  private
    FDesignConnection: Boolean;
    FSQLProcessor: TDBXSQLProcessor;
    FPoolOptions: TLXResourcePoolOptions;
    FPoolResource: TLXResource;
    procedure SetSQLProcessor(const Value: TDBXSQLProcessor);
    function GetActiveSQLProcessor: TDBXSQLProcessor;
    function GetVersion: string;
    procedure SetPoolOptions(const Value: TLXResourcePoolOptions);
    procedure SetVersion(const Value: string);
    function DefaultTransationDesc: TTransactionDesc;
  protected
    procedure Loaded; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure DoConnect; override;
    procedure DoDisconnect; override;
  public
    class procedure DeletePools(AsyncDelete: Boolean = True);
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    procedure AssignParams(Source: TSQLConnection);
    function GetPoolStats: TLXResourcePoolStats;
    procedure DeletePool(AsyncDelete: Boolean = True);
    procedure StartTransaction; overload;
    procedure Commit; overload;
    procedure Rollback; overload;
    procedure ApplyUpdates(const DataSets: array of TCustomSQLDataSet);
    property ActiveSQLProcessor: TDBXSQLProcessor read GetActiveSQLProcessor;
  published
    property DesignConnection: Boolean read FDesignConnection write FDesignConnection default False;
    property SQLProcessor: TDBXSQLProcessor read FSQLProcessor write SetSQLProcessor;
    property PoolOptions: TLXResourcePoolOptions read FPoolOptions write SetPoolOptions;  
    property Version: string read GetVersion write SetVersion stored False;
  end;


implementation

uses SysUtils{$IFDEF D10}, WideStrings{$ENDIF}, DB, SqlConst, DBXConsts,
  DBXEvents, DBXDataSetImpl;


type

{$IFDEF D10}
  TStringParams = TWideStrings;
  TStringParamList = TWideStringList;
{$ELSE}
  TStringParams = TStrings;
  TStringParamList = TStringList;
  ISQLConnection25 = ISQLConnection;
  ISQLCommand25 = ISQLCommand;
  ISQLMetaData25 = ISQLMetaData;
{$ENDIF}

{ TDBXAbstractConnectionParams }

  TDBXAbstractConnectionParams = class(TLXPoolResourceFactory)
  protected
    function GetDriverName: string; virtual; abstract;
    function GetLibraryName: string; virtual; abstract;
    function GetDriverFunc: string; virtual; abstract;
    function GetVendorLib: string; virtual; abstract;
    function GetParams: TStringParams; virtual; abstract;
  public
    procedure Release; override;
    function Equals(ResourceFactory: TLXPoolResourceFactory): Boolean; override;
    function CreateClone: TLXPoolResourceFactory; override;
    function CreateResource(const AcquireParams: array of const;
      Collector: TLXResourceCollector): TLXResource; override;
    property DriverName: string read GetDriverName;
    property LibraryName: string read GetLibraryName;
    property DriverFunc: string read GetDriverFunc;
    property VendorLib: string read GetVendorLib;
    property Params: TStringParams read GetParams;
  end;


{ TDBXConnectionParams }

  TDBXConnectionParams = class(TDBXAbstractConnectionParams)
  private
    FConnection: TDBXConnection;
  protected
    function GetDriverName: string; override;
    function GetLibraryName: string; override;
    function GetDriverFunc: string; override;
    function GetVendorLib: string; override;
    function GetParams: TStringParams; override;
  public
    constructor Create(Connection: TDBXConnection);
    function PoolOptions: TLXResourcePoolOptions; override;
  end;


{ TDBXPoolConnectionParams }

  TDBXPoolConnectionParams = class(TDBXAbstractConnectionParams)
  private
    FDriverName: string;
    FLibraryName: string;
    FDriverFunc: string;
    FVendorLib: string;
    FParams: TStringParams;
    FPoolOptions: TLXResourcePoolOptions;
  protected
    function GetDriverName: string; override;
    function GetLibraryName: string; override;
    function GetDriverFunc: string; override;
    function GetVendorLib: string; override;
    function GetParams: TStringParams; override;
  public
    constructor Create(Params: TDBXAbstractConnectionParams);
    destructor Destroy; override;
    function PoolOptions: TLXResourcePoolOptions; override;
  end;


{ TDBXPooledDriverProxy }

  TDBXPooledDriverProxy = class(TLXResourceBase, ISQLDriver)
  private
    FSQLDriver: ISQLDriver;
    FSQLConnection: ISQLConnection;
  protected
    procedure PrepareCollect; override;
    { IUnknown }
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    { ISQLDriver }
    function getSQLConnection(out pConn: ISQLConnection): SQLResult; stdcall;
    function SetOption(eDOption: TSQLDriverOption; PropValue: LongInt): SQLResult; stdcall;
    function GetOption(eDOption: TSQLDriverOption; PropValue: Pointer;
      MaxLength: SmallInt; out Length: SmallInt): SQLResult; stdcall;
  public
    constructor Create(Collector: TLXResourceCollector;
      Params: TDBXAbstractConnectionParams; const AcquireParams: array of const);
    destructor Destroy; override;
    procedure Acquire(const Params: array of const); override;
    property SQLConnection: ISQLConnection read FSQLConnection;
 end;


{ TDBXPooledConnectionProxy25 }

  TDBXPooledConnectionProxy25 = class(TInterfacedObject, ISQLConnection25)
  private
    FSQLConnection: ISQLConnection25;
  protected
    { ISQLConnection25 }
    function connect(ServerName, UserName, Password: PChar): SQLResult; stdcall;
    function disconnect: SQLResult; stdcall;
    function getSQLCommand(out pComm: ISQLCommand25): SQLResult; stdcall;
    function getSQLMetaData(out pMetaData: ISQLMetaData25): SQLResult; stdcall;
    function SetOption(eConnectOption: TSQLConnectionOption; lValue: LongInt): SQLResult; overload; stdcall;
    function GetOption(eDOption: TSQLConnectionOption; PropValue: Pointer;
      MaxLength: SmallInt; out Length: SmallInt): SQLResult; overload; stdcall;
    function beginTransaction(TranID: LongWord): SQLResult; stdcall;
    function commit(TranID: LongWord): SQLResult; stdcall;
    function rollback(TranID: LongWord): SQLResult; stdcall;
    function getErrorMessage(Error: PChar): SQLResult; overload; stdcall;
    function getErrorMessageLen(out ErrorLen: SmallInt): SQLResult; stdcall;
  public
    constructor Create(SQLConnection: ISQLConnection25);
    destructor Destroy; override;
 end;


{$IFDEF D10}

{ TDBXPooledConnectionProxy30 }

  TDBXPooledConnectionProxy30 = class(TInterfacedObject, ISQLConnection30)
  private
    FSQLConnection: ISQLConnection30;
  protected
    { ISQLConnection30 }
    function connect: SQLResult; overload; stdcall;
    function connect(ServerName, UserName, Password: PWideChar): SQLResult; overload; stdcall;
    function disconnect: SQLResult; stdcall;
    function getSQLCommand(out pComm: ISQLCommand30): SQLResult; stdcall;
    function getSQLMetaData(out pMetaData: ISQLMetaData30): SQLResult; stdcall;
    function SetOption(eConnectOption: TSQLConnectionOption; lValue: LongInt): SQLResult; overload; stdcall;
    function GetOption(eDOption: TSQLConnectionOption; PropValue: Pointer;
      MaxLength: SmallInt; out Length: SmallInt): SQLResult; overload; stdcall;
    function beginTransaction(TranID: LongWord): SQLResult; stdcall;
    function commit(TranID: LongWord): SQLResult; stdcall;
    function rollback(TranID: LongWord): SQLResult; stdcall;
    function getErrorMessage(Error: PWideChar): SQLResult; overload; stdcall;
    function getErrorMessageLen(out ErrorLen: SmallInt): SQLResult; stdcall;
  public
    constructor Create(SQLConnection: ISQLConnection30);
    destructor Destroy; override;
 end;

{$ENDIF}


{ TDBXAbstractConnectionParams }

procedure TDBXAbstractConnectionParams.Release;
begin
  Free;
end;

function TDBXAbstractConnectionParams.Equals(ResourceFactory: TLXPoolResourceFactory): Boolean;
begin
  with ResourceFactory as TDBXAbstractConnectionParams do
    Result := PoolOptions.Equals(Self.PoolOptions) and
      (DriverName = Self.DriverName) and (LibraryName = Self.LibraryName) and
      (DriverFunc = Self.DriverFunc) and (VendorLib = Self.VendorLib) and
      Params.Equals(Self.Params);
end;

function TDBXAbstractConnectionParams.CreateClone: TLXPoolResourceFactory;
begin
  Result := TDBXPoolConnectionParams.Create(Self);
end;

function TDBXAbstractConnectionParams.CreateResource(
  const AcquireParams: array of const; Collector: TLXResourceCollector): TLXResource;
begin
  Result := TDBXPooledDriverProxy.Create(Collector, Self, AcquireParams);
end;


{ TDBXConnectionParams }

constructor TDBXConnectionParams.Create(Connection: TDBXConnection);
begin
  FConnection := Connection;
end;

function TDBXConnectionParams.GetDriverName: string;
begin
  Result := FConnection.DriverName;
end;

function TDBXConnectionParams.GetLibraryName: string;
begin
  Result := FConnection.LibraryName;
end;

function TDBXConnectionParams.GetDriverFunc: string;
begin
  Result := FConnection.GetDriverFunc;
end;

function TDBXConnectionParams.GetVendorLib: string;
begin
  Result := FConnection.VendorLib;
end;

function TDBXConnectionParams.GetParams: TStringParams;
begin
  Result := FConnection.Params;
end;

function TDBXConnectionParams.PoolOptions: TLXResourcePoolOptions;
begin
  Result := FConnection.PoolOptions;
end;


{ TDBXPoolConnectionParams }

constructor TDBXPoolConnectionParams.Create(Params: TDBXAbstractConnectionParams);
begin
  FParams := TStringParamList.Create;
  FPoolOptions := TLXResourcePoolOptions.Create;

  FDriverName := Params.DriverName;
  FLibraryName := Params.LibraryName;
  FDriverFunc := Params.DriverFunc;
  FVendorLib := Params.VendorLib;
  FParams.Assign(Params.Params);
  FPoolOptions.Assign(Params.PoolOptions);
end;

destructor TDBXPoolConnectionParams.Destroy;
begin
  FParams.Free;
  FPoolOptions.Free;
end;

function TDBXPoolConnectionParams.GetDriverName: string;
begin
  Result := FDriverName;
end;

function TDBXPoolConnectionParams.GetLibraryName: string;
begin
  Result := FLibraryName;
end;

function TDBXPoolConnectionParams.GetDriverFunc: string;
begin
  Result := FDriverFunc;
end;

function TDBXPoolConnectionParams.GetVendorLib: string;
begin
  Result := FVendorLib;
end;

function TDBXPoolConnectionParams.GetParams: TStringParams;
begin
  Result := FParams;
end;

function TDBXPoolConnectionParams.PoolOptions: TLXResourcePoolOptions;
begin
  Result := FPoolOptions;
end;


{ TDBXPooledDriverProxy }

type
  TSQLConnectionChild = class(TSQLConnection);

{$IFDEF D10}
  TISQLConnectionFake = class(TISQLConnection)
  private
    I: ISQLConnection;
  end;
{$ENDIF}

constructor TDBXPooledDriverProxy.Create(Collector: TLXResourceCollector;
  Params: TDBXAbstractConnectionParams; const AcquireParams: array of const);
var
  SQLConnection: TSQLConnectionChild;
begin
  inherited Create(Collector);

  SQLConnection := TSQLConnectionChild.Create(nil);
  try
    SQLConnection.DriverName := Params.DriverName;
    SQLConnection.LibraryName := Params.LibraryName;
    SQLConnection.GetDriverFunc := Params.DriverFunc;
    SQLConnection.VendorLib := Params.VendorLib;
    SQLConnection.Params.Assign(Params.Params);
    SQLConnection.LoginPrompt := False;
    SQLConnection.Open;
    FSQLDriver := SQLConnection.Driver;
{$IFDEF D10}
    if SQLConnection.SQLConnection.ClassNameIs('TISQLConnection25') then
      ISQLConnection25(FSQLConnection) := TDBXPooledConnectionProxy25.Create(
        ISQLConnection25(TISQLConnectionFake(SQLConnection.SQLConnection).I))
    else
      ISQLConnection30(FSQLConnection) := TDBXPooledConnectionProxy30.Create(
        ISQLConnection30(TISQLConnectionFake(SQLConnection.SQLConnection).I));
    TISQLConnectionFake(SQLConnection.SQLConnection).I := FSQLConnection;
{$ELSE}
    FSQLConnection := TDBXPooledConnectionProxy25.Create(SQLConnection.SQLConnection);
    SQLConnection.SQLConnection := FSQLConnection;
{$ENDIF}
  finally
    SQLConnection.Free;
  end;
end;

destructor TDBXPooledDriverProxy.Destroy;
begin
  FSQLConnection := nil;
  try
    FSQLDriver := nil;
  except
    Pointer(FSQLDriver) := nil;
  end;
end;

procedure TDBXPooledDriverProxy.Acquire(const Params: array of const);
begin
end;

procedure TDBXPooledDriverProxy.PrepareCollect;
begin
end;

{ TDBXPooledDriver.IUnknown }

function TDBXPooledDriverProxy.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
end;

function TDBXPooledDriverProxy._AddRef: Integer;
begin
  Result := -1;
end;

function TDBXPooledDriverProxy._Release: Integer;
begin
  Result := -1;
  if Result = 0 then Destroy;
end;

{ TDBXPooledDriver.ISQLDriver }

const
  DBX_SUCCESS = 0;

function TDBXPooledDriverProxy.getSQLConnection(out pConn: ISQLConnection): SQLResult;
begin
  pConn := FSQLConnection;
  Result := DBX_SUCCESS;
end;

function TDBXPooledDriverProxy.SetOption(eDOption: TSQLDriverOption; PropValue: LongInt): SQLResult;
begin
  Result := FSQLDriver.SetOption(eDOption, PropValue);
end;

function TDBXPooledDriverProxy.GetOption(eDOption: TSQLDriverOption; PropValue: Pointer;
  MaxLength: SmallInt; out Length: SmallInt): SQLResult;
begin
  Result := FSQLDriver.GetOption(eDOption, PropValue, MaxLength, Length);
end;


{ TDBXPooledConnectionProxy25 }

constructor TDBXPooledConnectionProxy25.Create(SQLConnection: ISQLConnection25);
begin
  FSQLConnection := SQLConnection;
end;

destructor TDBXPooledConnectionProxy25.Destroy;
begin
  try
    FSQLConnection.disconnect;
  except
  end;
  try
    FSQLConnection := nil;
  except
    Pointer(FSQLConnection) := nil;
  end;
end;

{ TDBXPooledConnectionProxy25.ISQLConnection25 }

function TDBXPooledConnectionProxy25.connect(ServerName, UserName, Password: PChar): SQLResult;
begin
  Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy25.disconnect: SQLResult;
begin
  Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy25.getSQLCommand(out pComm: ISQLCommand25): SQLResult;
begin
  Result := FSQLConnection.getSQLCommand(pComm);
end;

function TDBXPooledConnectionProxy25.getSQLMetaData(out pMetaData: ISQLMetaData25): SQLResult;
begin
  Result := FSQLConnection.getSQLMetaData(pMetaData);
end;

function TDBXPooledConnectionProxy25.SetOption(eConnectOption: TSQLConnectionOption; lValue: LongInt): SQLResult;
begin
  if eConnectOption in [eConnCallBack, eConnCallBackInfo{$IFDEF D7}, eConnQualifiedName{$ENDIF}] then
    Result := FSQLConnection.SetOption(eConnectOption, lValue) else
    Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy25.GetOption(eDOption: TSQLConnectionOption; PropValue: Pointer;
  MaxLength: SmallInt; out Length: SmallInt): SQLResult;
begin
  Result := FSQLConnection.GetOption(eDOption, PropValue, MaxLength, Length);
end;

function TDBXPooledConnectionProxy25.beginTransaction(TranID: LongWord): SQLResult;
begin
  Result := FSQLConnection.beginTransaction(TranID);
end;

function TDBXPooledConnectionProxy25.commit(TranID: LongWord): SQLResult;
begin
  Result := FSQLConnection.commit(TranID);
end;

function TDBXPooledConnectionProxy25.rollback(TranID: LongWord): SQLResult;
begin
  Result := FSQLConnection.rollback(TranID);
end;

function TDBXPooledConnectionProxy25.getErrorMessage(Error: PChar): SQLResult;
begin
  Result := FSQLConnection.getErrorMessage(Error);
end;

function TDBXPooledConnectionProxy25.getErrorMessageLen(out ErrorLen: SmallInt): SQLResult;
begin
  Result := FSQLConnection.getErrorMessageLen(ErrorLen);
end;


{$IFDEF D10}

{ TDBXPooledConnectionProxy30 }

constructor TDBXPooledConnectionProxy30.Create(SQLConnection: ISQLConnection30);
begin
  FSQLConnection := SQLConnection;
end;

destructor TDBXPooledConnectionProxy30.Destroy;
begin
  try
    FSQLConnection.disconnect;
  except
  end;
  try
    FSQLConnection := nil;
  except
    Pointer(FSQLConnection) := nil;
  end;
end;

{ TDBXPooledConnectionProxy30.ISQLConnection30 }

function TDBXPooledConnectionProxy30.connect: SQLResult;
begin
  Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy30.connect(ServerName, UserName, Password: PWideChar): SQLResult;
begin
  Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy30.disconnect: SQLResult;
begin
  Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy30.getSQLCommand(out pComm: ISQLCommand30): SQLResult;
begin
  Result := FSQLConnection.getSQLCommand(pComm);
end;

function TDBXPooledConnectionProxy30.getSQLMetaData(out pMetaData: ISQLMetaData30): SQLResult;
begin
  Result := FSQLConnection.getSQLMetaData(pMetaData);
end;

function TDBXPooledConnectionProxy30.SetOption(eConnectOption: TSQLConnectionOption; lValue: LongInt): SQLResult;
begin
  if eConnectOption in [eConnCallBack, eConnCallBackInfo{$IFDEF D7}, eConnQualifiedName{$ENDIF}] then
    Result := FSQLConnection.SetOption(eConnectOption, lValue) else
    Result := DBX_SUCCESS;
end;

function TDBXPooledConnectionProxy30.GetOption(eDOption: TSQLConnectionOption; PropValue: Pointer;
  MaxLength: SmallInt; out Length: SmallInt): SQLResult;
begin
  Result := FSQLConnection.GetOption(eDOption, PropValue, MaxLength, Length);
end;

function TDBXPooledConnectionProxy30.beginTransaction(TranID: LongWord): SQLResult;
begin
  Result := FSQLConnection.beginTransaction(TranID);
end;

function TDBXPooledConnectionProxy30.commit(TranID: LongWord): SQLResult;
begin
  Result := FSQLConnection.commit(TranID);
end;

function TDBXPooledConnectionProxy30.rollback(TranID: LongWord): SQLResult;
begin
  Result := FSQLConnection.rollback(TranID);
end;

function TDBXPooledConnectionProxy30.getErrorMessage(Error: PWideChar): SQLResult;
begin
  Result := FSQLConnection.getErrorMessage(Error);
end;

function TDBXPooledConnectionProxy30.getErrorMessageLen(out ErrorLen: SmallInt): SQLResult;
begin
  Result := FSQLConnection.getErrorMessageLen(ErrorLen);
end;

{$ENDIF}


{ TDBXConnection }

var
  globalConnectionPools: TLXResourcePools;

class procedure TDBXConnection.DeletePools(AsyncDelete: Boolean);
begin
  globalConnectionPools.DeletePools(AsyncDelete);
end;

constructor TDBXConnection.Create(AOwner: TComponent);
begin
  inherited;
  FPoolOptions := TLXResourcePoolOptions.Create;
end;

destructor TDBXConnection.Destroy;
begin
  SetSQLProcessor(nil);
  FPoolOptions.Free;
  inherited;
end;

procedure TDBXConnection.AfterConstruction;
begin
  inherited;
  TDBXEvents.HandleObjectCreate(Self);
end;

procedure TDBXConnection.BeforeDestruction;
begin
  TDBXEvents.HandleObjectDestroy(Self);
  inherited;
end;

procedure TDBXConnection.SetSQLProcessor(const Value: TDBXSQLProcessor);
begin
  if FSQLProcessor <> nil then
    FSQLProcessor.RemoveFreeNotification(Self);
  FSQLProcessor := Value;
  if FSQLProcessor <> nil then
    FSQLProcessor.FreeNotification(Self);
end;

function TDBXConnection.GetActiveSQLProcessor: TDBXSQLProcessor;
begin
  Result := FSQLProcessor;
  if Result = nil then
    Result := TDBXSQLProcessor.DefaultProcessor;
end;

procedure TDBXConnection.SetPoolOptions(const Value: TLXResourcePoolOptions);
begin
  FPoolOptions.Assign(Value);
end;

function TDBXConnection.GetVersion: string;
begin
  Result := DBXVersion;
end;

procedure TDBXConnection.SetVersion(const Value: string);
begin
end;

function TDBXConnection.DefaultTransationDesc: TTransactionDesc;
var
  TransIsolationKey: string;
begin
  FillChar(Result, Sizeof(Result), 0);
  Result.TransactionID := 1;
  Result.IsolationLevel := xilReadCommitted;
  TransIsolationKey := Format(TRANSISOLATION_KEY, [DriverName]);
  if Params.Values[TransIsolationKey] <> '' then
    if LowerCase(Params.Values[TransIsolationKey]) = SRepeatRead then
      Result.IsolationLevel := xilRepeatableRead
    else if LowerCase(Params.Values[TransIsolationKey]) = SDirtyRead then
      Result.IsolationLevel := xilDirtyRead;
end;

procedure TDBXConnection.Loaded;
begin
  if FDesignConnection and not (csDesigning in ComponentState) then
    StreamedConnected := False;
  inherited;
end;

procedure TDBXConnection.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  if (AComponent = FSQLProcessor) and (Operation = opRemove) then
    FSQLProcessor := nil;
end;

threadvar
  globalDriver: ISQLDriver;

function GetGlobalDriver(SVendorLib, SResourceFile: PChar; out Obj): SQLResult; stdcall;
begin
  ISQLDriver(Obj) := globalDriver;
  Result := DBX_SUCCESS;
end;

procedure TDBXConnection.DoConnect;
var
  PoolParams: TDBXConnectionParams;
  SaveDllHandle: THandle;
  SaveGetDriver: Pointer;
begin
  if not FPoolOptions.Enabled then
    inherited else
  begin
    PoolParams := TDBXConnectionParams.Create(Self);
    try
      FPoolResource := globalConnectionPools.AllocateResource(PoolParams, []);
    finally
      PoolParams.Free;
    end;
    globalDriver := TDBXPooledDriverProxy(FPoolResource);
    SaveDllHandle := DllHandle;
    SaveGetDriver := @GetDriver;
    DllHandle := THandle(1);
    GetDriver := GetGlobalDriver;
    try
      inherited;
    finally
      globalDriver := nil;
      DllHandle := SaveDllHandle;
      GetDriver := SaveGetDriver;
    end;
  end;
end;

procedure TDBXConnection.DoDisconnect;
begin
  inherited;

  if FPoolResource <> nil then
  begin
    FPoolResource.Release;
    FPoolResource := nil;
  end;
end;

procedure TDBXConnection.AssignParams(Source: TSQLConnection);
begin
  DriverName := Source.DriverName;
  LibraryName := Source.LibraryName;
  GetDriverFunc := Source.GetDriverFunc;
  VendorLib := Source.VendorLib;
  Params.Assign(Source.Params);
  if Source is TDBXConnection then
    PoolOptions.Assign(TDBXConnection(Source).PoolOptions);
end;

function TDBXConnection.GetPoolStats: TLXResourcePoolStats;
var
  PoolParams: TDBXConnectionParams;
begin
  PoolParams := TDBXConnectionParams.Create(Self);
  try
    Result := globalConnectionPools.GetPoolStats(PoolParams);
  finally
    PoolParams.Free;
  end;
end;

procedure TDBXConnection.DeletePool(AsyncDelete: Boolean);
var
  PoolParams: TDBXConnectionParams;
begin
  PoolParams := TDBXConnectionParams.Create(Self);
  try
    globalConnectionPools.DeletePool(PoolParams, AsyncDelete);
  finally
    PoolParams.Free;
  end;
end;

procedure TDBXConnection.StartTransaction;
begin
  StartTransaction(DefaultTransationDesc);
end;

procedure TDBXConnection.Commit;
begin
  Commit(DefaultTransationDesc);
end;

procedure TDBXConnection.Rollback;
begin
  Rollback(DefaultTransationDesc);
end;

procedure TDBXConnection.ApplyUpdates(const DataSets: array of TCustomSQLDataSet);
var
  I: Integer;
begin
  if Length(DataSets) = 0 then Exit;

  for I := 0 to High(DataSets) do
    if DataSets[I].SQLConnection <> Self then
      DatabaseError(Format(SUpdateWrongDatabase, [DataSets[I].Name, Name]));

  IProviderSupport(DataSets[0]).PSStartTransaction;
  try
    for I := 0 to High(DataSets) do
      (DataSets[I] as IDBXDataSetExtension).ApplyUpdates(False);
    IProviderSupport(DataSets[0]).PSEndTransaction(True);
  except
    IProviderSupport(DataSets[0]).PSEndTransaction(False);
    raise;
  end;
  for I := 0 to High(DataSets) do
    (DataSets[I] as IDBXDataSetExtension).CommitUpdates;
end;


initialization
  globalConnectionPools := TLXResourcePools.Create;

finalization
  globalConnectionPools.Free;

end.